package com.zhou.base.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.MDC;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.annotation.AsyncConfigurerSupport;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.util.Map;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 类名
 *
 * @author zcy
 * @version $: AsyncConfig.java v1.0  2022年04月06日 17:54:32 $
 * @name 类名
 */
@Slf4j
@EnableAsync
@Component
public class AsyncConfig extends AsyncConfigurerSupport {
	/**
	 * 根据cpu的数量动态的配置核心线程数和最大线程数
	 */
	private static final int CPU_COUNT    = Runtime.getRuntime().availableProcessors();

	/**
	 * 核心线程数 = CPU核心数 + 1
	 */
	private static final int CORE_POOL_SIZE    = CPU_COUNT + 1;
	/**
	 * 线程池最大线程数 = CPU核心数 * 2 + 1
	 */
	private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
	/**
	 * 非核心线程闲置时超时1s
	 */
	private static final int KEEP_ALIVE        = 1;

	//异步线程池
	@Override
	@Bean(name = "asyncExecutor")
	public AsyncTaskExecutor getAsyncExecutor() {
		ThreadFactory threadFactory =  new BasicThreadFactory.Builder().uncaughtExceptionHandler(new MyThreadException()).build();
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
		executor.setThreadFactory(threadFactory);
		executor.setCorePoolSize(CORE_POOL_SIZE);
		executor.setMaxPoolSize(MAXIMUM_POOL_SIZE);
		executor.setKeepAliveSeconds(KEEP_ALIVE);
		executor.setQueueCapacity(CPU_COUNT);
		executor.setThreadNamePrefix("executor-");
		executor.setTaskDecorator(runnable -> {
			try {
				RequestAttributes context = RequestContextHolder.currentRequestAttributes();  //1
//				FrontUser frontUser = SecurityContext.getFrontUser();
//				SysUserInfo user = SecurityContext.getUser();
				Map<String, String> copyOfContextMap = MDC.getCopyOfContextMap();
				return () -> {
					try {
						RequestContextHolder.setRequestAttributes(context,true);	 //1
//						SecurityContext.setFrontUser(frontUser);   //3
//						SecurityContext.setUser(user);
						MDC.setContextMap(copyOfContextMap);
						runnable.run();
					} finally {
						RequestContextHolder.resetRequestAttributes();		// 1
//						SecurityContext.clear();				// 3
						MDC.clear();
					}
				};
			} catch (IllegalStateException e) {
				return runnable;
			}
		});
		// rejection-policy：当pool已经达到max size的时候，如何处理新任务
		// CALLER_RUNS：不在新线程中执行任务，而是由调用者所在的线程来执行
		//对拒绝task的处理策略
		executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
		executor.initialize();
		return executor;
	}
	class MyThreadException implements Thread.UncaughtExceptionHandler{
		@Override
		public void uncaughtException(Thread t, Throwable e) {
			log.error("myException"+ ExceptionUtils.getStackTrace(e));
		}
	}

	/**
	 * 如果本方法返回为空，则使用 SimpleAsyncUncaughtExceptionHandler 只打印异常信息
	 *
	 * @return
	 */
	@Override
	public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
		return super.getAsyncUncaughtExceptionHandler();
	}
}
